Setup

Load libraries

library(ggplot2)
library(tidyr)
library(dplyr)
library(Matrix)
library(Seurat)
library(cowplot)
library(patchwork)

Process Human Data

import_remote_data <- function(file_url, type = "table", header = FALSE) {
  con <- gzcon(url(file_url))
  txt <- readLines(con)
  if (type == "MM") { return (readMM(textConnection(txt))) }
  if (type == "table") { return (read.table(textConnection(txt), header = header)) }
}

count_matrix_URL <- "https://ftp.ncbi.nlm.nih.gov/geo/series/GSE137nnn/GSE137537/suppl/GSE137537_counts.mtx.gz"
gene_names_URL <- "https://ftp.ncbi.nlm.nih.gov/geo/series/GSE137nnn/GSE137537/suppl/GSE137537_gene_names.txt.gz"
sample_annotations_URL <- "https://ftp.ncbi.nlm.nih.gov/geo/series/GSE137nnn/GSE137537/suppl/GSE137537_sample_annotations.tsv.gz"

count_matrix <- as.matrix(import_remote_data(count_matrix_URL, type = "MM"))
gene_names <- import_remote_data(gene_names_URL, type = "table")
sample_annotations <- import_remote_data(sample_annotations_URL, type = "table", header = TRUE)
rownames(count_matrix) <- tolower(gene_names[,1])
colnames(count_matrix) <- tolower(sample_annotations[,1])

human_ret_seurat <- CreateSeuratObject(counts = count_matrix, 
                                       meta.data = sample_annotations, 
                                       project = "human_ret", 
                                       min.cells = 3, 
                                       min.features = 200)
Some cells in meta.data not present in provided counts matrixNon-unique features (rownames) present in the input matrix, making uniqueFeature names cannot have underscores ('_'), replacing with dashes ('-')
human_ret_seurat
An object of class Seurat 
19712 features across 20091 samples within 1 assay 
Active assay: RNA (19712 features, 0 variable features)

Process Mouse Data

mouse.data <- Read10X(data.dir = "filtered_feature_bc_matrix")
dimnames(mouse.data)[[1]] <- tolower(dimnames(mouse.data)[[1]])
dimnames(mouse.data)[[2]] <- tolower(dimnames(mouse.data)[[2]])
mouse_ret_seurat <- CreateSeuratObject(counts = mouse.data, 
                                       project = "mouse_ret", 
                                       min.cells = 3, 
                                       min.features = 200)
mouse_ret_seurat
An object of class Seurat 
16424 features across 4510 samples within 1 assay 
Active assay: RNA (16424 features, 0 variable features)

Combine

ret.list <- list(human = human_ret_seurat, mouse = mouse_ret_seurat)

ret.list <- lapply(X = ret.list, FUN = function(x) {
    x <- NormalizeData(x, verbose = FALSE)
    x <- FindVariableFeatures(x, selection.method = "vst", nfeatures = 2000, verbose = FALSE)
})

Integration

ret.anchors <- FindIntegrationAnchors(object.list = ret.list, dims = 1:50,  anchor.features = 1000)
ret.combined <- IntegrateData(anchorset = ret.anchors, dims = 1:50)

Integrated Analysis

DefaultAssay(ret.combined) <- "integrated"

# Run the standard workflow for visualization and clustering
ret.combined <- ScaleData(ret.combined, verbose = FALSE)
ret.combined <- RunPCA(ret.combined, npcs = 50, verbose = FALSE)
# t-SNE and Clustering
ret.combined <- RunUMAP(ret.combined, reduction = "pca", dims = 1:35)
ret.combined <- RunTSNE(ret.combined, reduction = "pca", dims = 1:35)
ret.combined <- FindNeighbors(ret.combined, reduction = "pca", dims = 1:35)
ret.combined <- FindClusters(ret.combined, resolution = 0.05)

UMAP Visualization

# Visualization
p1 <- DimPlot(ret.combined, reduction = "umap", group.by = "orig.ident")
p2 <- DimPlot(ret.combined, reduction = "umap", label = TRUE)
plot_grid(p1, p2)

DimPlot(ret.combined, reduction = "umap", split.by = "orig.ident")

TSNE Visualization

p1 <- DimPlot(ret.combined, reduction = "tsne", group.by = "orig.ident")
p2 <- DimPlot(ret.combined, reduction = "tsne", label = TRUE)
plot_grid(p1, p2)

DimPlot(ret.combined, reduction = "tsne", split.by = "orig.ident")

Identify Conserved Markers

max_cluster <- 8
marker.list <- as.list(c(0:max_cluster))
marker.list <- lapply(X = marker.list, FUN = function(x) {
  x <- FindConservedMarkers(ret.combined, ident.1 = x, grouping.var = "orig.ident", verbose = TRUE)
})
DefaultAssay(ret.combined) <- "RNA"
plots <- as.list(1:(max_cluster+1))
plots <- lapply(X = plots, FUN = function(x) {
  x <- FeaturePlot(ret.combined, features = rownames(marker.list[[x]])[1:6], min.cutoff = "q9")
})
for (i in seq_along(plots)) {
  t <- sprintf("Cluster %d", (i-1))
  p <- plots[[i]] + plot_annotation(title = t)
  print(p)
  #print(sprintf("Cluster %d", (i-1))
  #plot(plots[[i]])
}

LS0tCnRpdGxlOiAiQ29tcGFyaXNvbiBvZiB0aGUgVHJhbnNjcmlwdG9taWMgQXRsYXMgb2YgdGhlIEh1bWFuIFJldGluYSBhbmQgTW91c2UgUmV0aW5hIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCiMgU2V0dXAKTG9hZCBsaWJyYXJpZXMKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KE1hdHJpeCkKbGlicmFyeShTZXVyYXQpCmxpYnJhcnkoY293cGxvdCkKbGlicmFyeShwYXRjaHdvcmspCmBgYApQcm9jZXNzIEh1bWFuIERhdGEKYGBge3J9CmltcG9ydF9yZW1vdGVfZGF0YSA8LSBmdW5jdGlvbihmaWxlX3VybCwgdHlwZSA9ICJ0YWJsZSIsIGhlYWRlciA9IEZBTFNFKSB7CiAgY29uIDwtIGd6Y29uKHVybChmaWxlX3VybCkpCiAgdHh0IDwtIHJlYWRMaW5lcyhjb24pCiAgaWYgKHR5cGUgPT0gIk1NIikgeyByZXR1cm4gKHJlYWRNTSh0ZXh0Q29ubmVjdGlvbih0eHQpKSkgfQogIGlmICh0eXBlID09ICJ0YWJsZSIpIHsgcmV0dXJuIChyZWFkLnRhYmxlKHRleHRDb25uZWN0aW9uKHR4dCksIGhlYWRlciA9IGhlYWRlcikpIH0KfQoKY291bnRfbWF0cml4X1VSTCA8LSAiaHR0cHM6Ly9mdHAubmNiaS5ubG0ubmloLmdvdi9nZW8vc2VyaWVzL0dTRTEzN25ubi9HU0UxMzc1Mzcvc3VwcGwvR1NFMTM3NTM3X2NvdW50cy5tdHguZ3oiCmdlbmVfbmFtZXNfVVJMIDwtICJodHRwczovL2Z0cC5uY2JpLm5sbS5uaWguZ292L2dlby9zZXJpZXMvR1NFMTM3bm5uL0dTRTEzNzUzNy9zdXBwbC9HU0UxMzc1MzdfZ2VuZV9uYW1lcy50eHQuZ3oiCnNhbXBsZV9hbm5vdGF0aW9uc19VUkwgPC0gImh0dHBzOi8vZnRwLm5jYmkubmxtLm5paC5nb3YvZ2VvL3Nlcmllcy9HU0UxMzdubm4vR1NFMTM3NTM3L3N1cHBsL0dTRTEzNzUzN19zYW1wbGVfYW5ub3RhdGlvbnMudHN2Lmd6IgoKY291bnRfbWF0cml4IDwtIGFzLm1hdHJpeChpbXBvcnRfcmVtb3RlX2RhdGEoY291bnRfbWF0cml4X1VSTCwgdHlwZSA9ICJNTSIpKQpnZW5lX25hbWVzIDwtIGltcG9ydF9yZW1vdGVfZGF0YShnZW5lX25hbWVzX1VSTCwgdHlwZSA9ICJ0YWJsZSIpCnNhbXBsZV9hbm5vdGF0aW9ucyA8LSBpbXBvcnRfcmVtb3RlX2RhdGEoc2FtcGxlX2Fubm90YXRpb25zX1VSTCwgdHlwZSA9ICJ0YWJsZSIsIGhlYWRlciA9IFRSVUUpCmBgYApgYGB7cn0Kcm93bmFtZXMoY291bnRfbWF0cml4KSA8LSB0b2xvd2VyKGdlbmVfbmFtZXNbLDFdKQpjb2xuYW1lcyhjb3VudF9tYXRyaXgpIDwtIHRvbG93ZXIoc2FtcGxlX2Fubm90YXRpb25zWywxXSkKCmh1bWFuX3JldF9zZXVyYXQgPC0gQ3JlYXRlU2V1cmF0T2JqZWN0KGNvdW50cyA9IGNvdW50X21hdHJpeCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1ldGEuZGF0YSA9IHNhbXBsZV9hbm5vdGF0aW9ucywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2plY3QgPSAiaHVtYW5fcmV0IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pbi5jZWxscyA9IDMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaW4uZmVhdHVyZXMgPSAyMDApCmh1bWFuX3JldF9zZXVyYXQKYGBgCgpQcm9jZXNzIE1vdXNlIERhdGEKYGBge3J9Cm1vdXNlLmRhdGEgPC0gUmVhZDEwWChkYXRhLmRpciA9ICJmaWx0ZXJlZF9mZWF0dXJlX2JjX21hdHJpeCIpCmRpbW5hbWVzKG1vdXNlLmRhdGEpW1sxXV0gPC0gdG9sb3dlcihkaW1uYW1lcyhtb3VzZS5kYXRhKVtbMV1dKQpkaW1uYW1lcyhtb3VzZS5kYXRhKVtbMl1dIDwtIHRvbG93ZXIoZGltbmFtZXMobW91c2UuZGF0YSlbWzJdXSkKbW91c2VfcmV0X3NldXJhdCA8LSBDcmVhdGVTZXVyYXRPYmplY3QoY291bnRzID0gbW91c2UuZGF0YSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2plY3QgPSAibW91c2VfcmV0IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pbi5jZWxscyA9IDMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaW4uZmVhdHVyZXMgPSAyMDApCm1vdXNlX3JldF9zZXVyYXQKYGBgCkNvbWJpbmUKYGBge3J9CnJldC5saXN0IDwtIGxpc3QoaHVtYW4gPSBodW1hbl9yZXRfc2V1cmF0LCBtb3VzZSA9IG1vdXNlX3JldF9zZXVyYXQpCgpyZXQubGlzdCA8LSBsYXBwbHkoWCA9IHJldC5saXN0LCBGVU4gPSBmdW5jdGlvbih4KSB7CiAgICB4IDwtIE5vcm1hbGl6ZURhdGEoeCwgdmVyYm9zZSA9IEZBTFNFKQogICAgeCA8LSBGaW5kVmFyaWFibGVGZWF0dXJlcyh4LCBzZWxlY3Rpb24ubWV0aG9kID0gInZzdCIsIG5mZWF0dXJlcyA9IDIwMDAsIHZlcmJvc2UgPSBGQUxTRSkKfSkKYGBgCgojIEludGVncmF0aW9uCmBgYHtyfQpyZXQuYW5jaG9ycyA8LSBGaW5kSW50ZWdyYXRpb25BbmNob3JzKG9iamVjdC5saXN0ID0gcmV0Lmxpc3QsIGRpbXMgPSAxOjUwLCAgYW5jaG9yLmZlYXR1cmVzID0gMTAwMCkKcmV0LmNvbWJpbmVkIDwtIEludGVncmF0ZURhdGEoYW5jaG9yc2V0ID0gcmV0LmFuY2hvcnMsIGRpbXMgPSAxOjUwKQpgYGAKCiMgSW50ZWdyYXRlZCBBbmFseXNpcwpgYGB7cn0KRGVmYXVsdEFzc2F5KHJldC5jb21iaW5lZCkgPC0gImludGVncmF0ZWQiCgojIFJ1biB0aGUgc3RhbmRhcmQgd29ya2Zsb3cgZm9yIHZpc3VhbGl6YXRpb24gYW5kIGNsdXN0ZXJpbmcKcmV0LmNvbWJpbmVkIDwtIFNjYWxlRGF0YShyZXQuY29tYmluZWQsIHZlcmJvc2UgPSBGQUxTRSkKcmV0LmNvbWJpbmVkIDwtIFJ1blBDQShyZXQuY29tYmluZWQsIG5wY3MgPSA1MCwgdmVyYm9zZSA9IEZBTFNFKQojIHQtU05FIGFuZCBDbHVzdGVyaW5nCnJldC5jb21iaW5lZCA8LSBSdW5VTUFQKHJldC5jb21iaW5lZCwgcmVkdWN0aW9uID0gInBjYSIsIGRpbXMgPSAxOjM1KQpyZXQuY29tYmluZWQgPC0gUnVuVFNORShyZXQuY29tYmluZWQsIHJlZHVjdGlvbiA9ICJwY2EiLCBkaW1zID0gMTozNSkKcmV0LmNvbWJpbmVkIDwtIEZpbmROZWlnaGJvcnMocmV0LmNvbWJpbmVkLCByZWR1Y3Rpb24gPSAicGNhIiwgZGltcyA9IDE6MzUpCnJldC5jb21iaW5lZCA8LSBGaW5kQ2x1c3RlcnMocmV0LmNvbWJpbmVkLCByZXNvbHV0aW9uID0gMC4wNSkKYGBgCiMgVU1BUCBWaXN1YWxpemF0aW9uCmBgYHtyfQojIFZpc3VhbGl6YXRpb24KcDEgPC0gRGltUGxvdChyZXQuY29tYmluZWQsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgZ3JvdXAuYnkgPSAib3JpZy5pZGVudCIpCnAyIDwtIERpbVBsb3QocmV0LmNvbWJpbmVkLCByZWR1Y3Rpb24gPSAidW1hcCIsIGxhYmVsID0gVFJVRSkKcGxvdF9ncmlkKHAxLCBwMikKYGBgCmBgYHtyfQpEaW1QbG90KHJldC5jb21iaW5lZCwgcmVkdWN0aW9uID0gInVtYXAiLCBzcGxpdC5ieSA9ICJvcmlnLmlkZW50IikKYGBgCgojIFRTTkUgVmlzdWFsaXphdGlvbgpgYGB7cn0KcDEgPC0gRGltUGxvdChyZXQuY29tYmluZWQsIHJlZHVjdGlvbiA9ICJ0c25lIiwgZ3JvdXAuYnkgPSAib3JpZy5pZGVudCIpCnAyIDwtIERpbVBsb3QocmV0LmNvbWJpbmVkLCByZWR1Y3Rpb24gPSAidHNuZSIsIGxhYmVsID0gVFJVRSkKcGxvdF9ncmlkKHAxLCBwMikKYGBgCmBgYHtyfQpEaW1QbG90KHJldC5jb21iaW5lZCwgcmVkdWN0aW9uID0gInRzbmUiLCBzcGxpdC5ieSA9ICJvcmlnLmlkZW50IikKYGBgCiMgSWRlbnRpZnkgQ29uc2VydmVkIE1hcmtlcnMKYGBge3J9Cm1heF9jbHVzdGVyIDwtIDgKbWFya2VyLmxpc3QgPC0gYXMubGlzdChjKDA6bWF4X2NsdXN0ZXIpKQptYXJrZXIubGlzdCA8LSBsYXBwbHkoWCA9IG1hcmtlci5saXN0LCBGVU4gPSBmdW5jdGlvbih4KSB7CiAgeCA8LSBGaW5kQ29uc2VydmVkTWFya2VycyhyZXQuY29tYmluZWQsIGlkZW50LjEgPSB4LCBncm91cGluZy52YXIgPSAib3JpZy5pZGVudCIsIHZlcmJvc2UgPSBUUlVFKQp9KQpgYGAKYGBge3J9CkRlZmF1bHRBc3NheShyZXQuY29tYmluZWQpIDwtICJSTkEiCnBsb3RzIDwtIGFzLmxpc3QoMToobWF4X2NsdXN0ZXIrMSkpCnBsb3RzIDwtIGxhcHBseShYID0gcGxvdHMsIEZVTiA9IGZ1bmN0aW9uKHgpIHsKICB4IDwtIEZlYXR1cmVQbG90KHJldC5jb21iaW5lZCwgZmVhdHVyZXMgPSByb3duYW1lcyhtYXJrZXIubGlzdFtbeF1dKVsxOjZdLCBtaW4uY3V0b2ZmID0gInE5IikKfSkKYGBgCmBgYHtyfQpmb3IgKGkgaW4gc2VxX2Fsb25nKHBsb3RzKSkgewogIHQgPC0gc3ByaW50ZigiQ2x1c3RlciAlZCIsIChpLTEpKQogIHAgPC0gcGxvdHNbW2ldXSArIHBsb3RfYW5ub3RhdGlvbih0aXRsZSA9IHQpCiAgcHJpbnQocCkKfQpgYGAKCgoKCg==